<?php
/*
Plugin Name: odReservationsWpPlugin
Plugin URI: http://www.ondrejd.info/projects/wordpress-plugins/od-registrations-plugin/
Description: Plugin pro rezervaci hracích časů www.golfline.cz.
Version: ##VERSION##
Author: Ondrej Donek
Author URI: http://www.ondrejd.info/
*/

/*  ***** BEGIN LICENSE BLOCK *****
    Version: MPL 1.1
    
    The contents of this file are subject to the Mozilla Public License Version 
    1.1 (the "License"); you may not use this file except in compliance with 
    the License. You may obtain a copy of the License at 
    http://www.mozilla.org/MPL/
    
    Software distributed under the License is distributed on an "AS IS" basis,
    WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    for the specific language governing rights and limitations under the
    License.
    
    The Original Code is odReservationsWpPlugin.
    
    The Initial Developer of the Original Code is
    Ondrej Donek.
    Portions created by the Initial Developer are Copyright (C) 2010
    the Initial Developer. All Rights Reserved.
    
    Contributor(s):
    
    ***** END LICENSE BLOCK ***** */

require_once realpath(dirname(__FILE__) . '/odWpPlugin.php');

#{{{ odReservationsWpPlugin_Models_Playground_Item ---
if(!class_exists('odReservationsWpPlugin_Models_Playground_Item')):
#!src_models_playground_Item##
endif;
#}}} --- odReservationsWpPlugin_Models_Playground_Item

#{{{ odReservationsWpPlugin_Models_Member_Item ---
if(!class_exists('odReservationsWpPlugin_Models_Member_Item')):
#!src_models_member_Item##
endif;
#}}} --- odReservationsWpPlugin_Models_Member_Item

#{{{ odReservationsWpPlugin_Models_Reservation_Item ---
if(!class_exists('odReservationsWpPlugin_Models_Reservation_Item')):
#!src_models_reservation_Item##
endif;
#}}} --- odReservationsWpPlugin_Models_Reservation_Item


#{{{ odReservationsWpPlugin_Models_Playground ---
if(!class_exists('odReservationsWpPlugin_Models_Playground')):
#!src_models_Playground##
endif;
#}}} --- odReservationsWpPlugin_Models_Playground


#{{{ odReservationsWpPlugin_Models_Member ---
if(!class_exists('odReservationsWpPlugin_Models_Member')):
#!src_models_Member##
endif;
#}}} --- odReservationsWpPlugin_Models_Member


#{{{ odReservationsWpPlugin_Models_Reservation ---
if(!class_exists('odReservationsWpPlugin_Models_Reservation')):
#!src_models_Reservation##
endif;
#}}} --- odReservationsWpPlugin_Models_Reservation


#{{{ odReservationsWpPlugin_Tables_Playground ---
if(!class_exists('odReservationsWpPlugin_Tables_Playground')):
#!src_tables_Playground##
endif;
#}}} --- odReservationsWpPlugin_Tables_Playground


#{{{ odReservationsWpPlugin_Tables_Member ---
if(!class_exists('odReservationsWpPlugin_Tables_Member')):
#!src_tables_Member##
endif;
#}}} --- odReservationsWpPlugin_Tables_Member


#{{{ odReservationsWpPlugin_Tables_Reservation ---
if(!class_exists('odReservationsWpPlugin_Tables_Reservation')):
#!src_tables_Reservation##
endif;
#}}} --- odReservationsWpPlugin_Tables_Reservation


#{{{ odReservationsWpPlugin_Forms_Reservation ---
if(!class_exists('odReservationsWpPlugin_Forms_Reservation')):
#!src_forms_Reservation##
endif;
#}}} --- odReservationsWpPlugin_Forms_Reservation


#{{{ odReservationsWpPlugin_Forms_Playground ---
if(!class_exists('odReservationsWpPlugin_Forms_Playground')):
#!src_forms_Playground##
endif;
#}}} --- odReservationsWpPlugin_Forms_Playground


#{{{ odReservationsWpPlugin_Forms_Member ---
if(!class_exists('odReservationsWpPlugin_Forms_Member')):
#!src_forms_Member##
endif;
#}}} --- odReservationsWpPlugin_Forms_Member


#{{{ odReservationsWpPlugin ---
if(!class_exists('odReservationsWpPlugin')):

/**
 * Main catalog object
 * 
 * @author Ondrej Donek, <ondrejd@gmail.com>
 * @package odReservationsWpPlugin
 * @version ##VERSION##
 */
class odReservationsWpPlugin extends odWpPlugin
{
	/**
	 * Constructor.
	 *
	 * @return void
	 */
	public function __construct()
	{
		parent::__construct(
			'od-reservations-wpplugin',
			'odReservationsWpPlugin',
			'##VERSION##', 
			array(
				'hasAdmin' => true,
				'adminConfig' => array(
					'stylesheet' => true
				),
				'hasLocales' => true,
				'hasOptions' => true, 
				'defaultOptions' => array(
          'default_playground_id' => 1
				)
			)
		);
		
		// Activation/deactivation
		register_activation_hook(__FILE__, array(&$this, 'activate'));
		register_deactivation_hook(__FILE__, array(&$this, 'deactivate'));
		
		// Ensure that plugin's options are initialized
		$options = $this->initOptions();
    
		// Ensure that exist's 'golfmember' user role
		$this->updateWpUserRoles(array(
			'golfmember' => array(
				'name' => 'Člen klubu',
				'capabilities' => array(
						'read' => 1,
						'level_0' => 1
				)
			)
		));
		
		if(is_admin()) {
      // Add our CSS and additional JavaScript files
      add_action('admin_head', array(&$this, 'adminHeader'));
      
			// TODO Add AJAX check for new galleries directories
			//add_action('admin_print_scripts', array(&$this, 'js_admin_header'));
			//add_action('wp_ajax_catalog_check_dir', array(&$this, 'ajax_check_if_dir_exist'));
			
			// Register admin menu
			add_action('admin_menu', array(&$this, 'adminMenu'));
			
			// TODO Register top quick admin menus
			
			// TODO Register TinyMCE buttons
			// add_action('init', array(&$this, 'register_tinymce_buttons'));
			
			// TODO Register our dashboard widget
		}
		else {
      // Register content filter
      //add_filter('the_content', array(&$this, 'contentFilter'));
      
      // Initialize plugin's widgets
      //register_widget('...');
    }
  }, // end __construct()
	
	/**
	 * Activates the plugin
	 * 
	 * @returns void
	 */
	public function activate()
	{
		// Collect plugins metric data
		$this->collectMetricsData(self::ID, self::VERSION, get_bloginfo('home'), 'activate');
		
		// Ensure that database tables are created
		$playgroundModel = new odReservationsWpPlugin_Models_Playground();
		$memberModel = new odReservationsWpPlugin_Models_Member();
    $reservationModel = new odReservationsWpPlugin_Models_Reservation();
		
		$playgroundModel->createTable();
		$memberModel->createTable();
    $reservationModel->createTable();
	} // end activate()

	/**
	 * Deactivates the plugin
	 * 
	 * @returns void
	 */
	public function deactivate()
	{
		// Collect plugins metric data
		$this->collectMetricsData(self::ID, self::VERSION, get_bloginfo('home'), 'deactivate');
		
		// TODO Destroy database if user want it! 
	} // end deactivate()
  
  /**
   * Add our CSS and additional JavaScript files to the header of admin 
   * HTML pages.
   * 
   * @returns void
   */
  public function adminHeader()
  {
    $this->mRenderer->addResources(
      array(
        $this->getResourceUrl('resources/js/jquery-ui-1.7.2.custom.min.js'),
        $this->getResourceUrl('resources/js/jquery.ui.datepicker-cs.js')
      ),
      array(
        $this->getResourceUrl('resources/css/jquery-ui-1.7.2.custom.css'),
        $this->getResourceUrl('resources/css/wp-admin.css')
      )
    );
  }
	
	/**
	 * Registers administration menu for the plugin
	 * 
	 * @returns void
	 */
	public function adminMenu() 
	{
    add_menu_page(
				__('Rezervace', self::TEXTDOMAIN),
				__('Rezervace', self::TEXTDOMAIN),
				0,
				self::ID,
				array(&$this, 'adminMain'),
				WP_PLUGIN_URL . '/' . self::ID . '/resources/icon16.png'
		);
		add_submenu_page(
				self::ID,
				__('Rezervace - Rezervace hry', self::TEXTDOMAIN),
				__('Rezervace hry', self::TEXTDOMAIN),
				0,
				self::ID . '-reservation',
				array(&$this, 'adminAddReservation')
		);
    
    if(!is_null($this->_get_logged_member())) {
      add_submenu_page(
          self::ID,
          __('Rezervace - Moje rezervace', self::TEXTDOMAIN),
          __('Moje rezervace', self::TEXTDOMAIN),
          0,
          self::ID . '-my_reservations',
          array(&$this, 'adminMyReservations')
      );
    }
    
    if($this->_is_logged_administrator() === true) {
      add_submenu_page(
          self::ID,
          __('Rezervace - Přehled', self::TEXTDOMAIN),
          __('Přehled rezervací', self::TEXTDOMAIN),
          0,
          self::ID . '-all_reservations',
          array(&$this, 'adminAllReservations')
      );
      add_submenu_page(
          self::ID,
          __('Rezervace - Uživatelé', self::TEXTDOMAIN),
          __('Uživatelé', self::TEXTDOMAIN),
          0,
          self::ID . '-members',
          array(&$this, 'adminMembers')
      );
      add_submenu_page(
          self::ID,
          __('Rezervace - Přidej uživatele', self::TEXTDOMAIN),
          __('Přidej uživatele', self::TEXTDOMAIN),
          0,
          self::ID . '-add_member',
          array(&$this, 'adminAddMember')
      );
      
      // {{{ Note: Zatim jen pro Honzu Kocourka a mne
      global $current_user;
      if($current_user->user_login == 'dylan2' || 
         $current_user->user_login == 'ondrejd' || 
         $current_user->user_login == 'ondra') {
        add_submenu_page(
            self::ID,
            __('Rezervace - Hřiště', self::TEXTDOMAIN),
            __('Hřiště', self::TEXTDOMAIN),
            0,
            self::ID . '-playgrounds',
            array(&$this, 'adminPlaygrounds')
        );
        add_submenu_page(
            self::ID,
            __('Rezervace - Přidej hřiště', self::TEXTDOMAIN),
            __('Přidej hřiště', self::TEXTDOMAIN),
            0,
            self::ID . '-add_playground',
            array(&$this, 'adminAddPlayground')
        );
      }
      
      add_submenu_page(
          self::ID,
          __('Rezervace - Nastavení', self::TEXTDOMAIN),
          __('Nastavení', self::TEXTDOMAIN),
          0,
          self::ID . '-settings',
          array(&$this, 'adminSettings')
      );
      // --- }}}
    }
	}
  
	/**
	 * Renders admin page with reservations.
	 * 
	 * @returns void
	 */
	public function adminMain()
	{
		//setlocale(LC_TIME, 'cs_CZ');
		$title = __('Rezervace', self::TEXTDOMAIN);
		$icon  = WP_PLUGIN_URL . '/' . self::ID . '/resources/icon32.png';
		$url = get_bloginfo('home') . '/wp-admin/admin.php?page=' . self::ID;
		$url1 = get_bloginfo('home') . '/wp-admin/admin.php?page=' . self::ID . '-reservation';
		$content = '';
		
    // Get default playground
    $playground = $this->_get_default_playground();
    if(is_null($playground)) {
      throw new Exception('Není nastaveno defaultní hřiště! Přejděte ' . 
                          'na stránku s nastavením pluginu a určete ' . 
                          'defaultní hřiště pro další pokračování.');
		}
    
    $_date = date('Y-m-d');
		$date = date('d.m.Y');
		$year = (array_key_exists('y', $_GET)) ? $_GET['y'] : date('Y');
		$month = (array_key_exists('m', $_GET)) ? $_GET['m'] : date('m');
		
		$prevYear = $year;
		$prevMonth = $month - 1;
		if($prevMonth < 1) {
			$prevMonth = 12;
			$prevYear = $prevYear - 1;
		}
		
		$nextYear = $year;
		$nextMonth = $month + 1;
		if($nextMonth > 12) {
			$nextMonth = 1;
			$nextYear = $nextYear + 1;
		}
		
		$firstday = 1;
		$firstdayIs = intval(date('N', strtotime($year . '-' . $month . '-01')));
		$lastday = intval(date('t', strtotime($year .'-' .$month)));
		
		$content .= '<h3>Rezervace pro hřiště <span style="text-decoration: underline;">' . $playground['title'] . '</span></h3>';
		$content .= '<div class="tablenav"><p style="text-align: center; margin-bottom: 0px;">' . 
				 '<a href="' . $url . '&amp;m=' . $prevMonth . '&amp;y=' . $prevYear . '" title="Předchozí měsíc">' . $prevYear . '-' . $this->_normalize_num($prevMonth) . '</a> | ' . 
				 '<strong>' . $year . '-' . $month . '</strong> | ' . 
				 '<a href="' . $url . '&amp;m=' . $nextMonth . '&amp;y=' . $nextYear . '" title="Následující měsíc">' . $nextYear . '-' . $this->_normalize_num($nextMonth) . '</a></p></div>';
		//$content .= '<br class="clear"/>' . PHP_EOL;
		$content .= '<table id="reservations_calendar-table" class="widefat post fixed" cellspacing="0">' . PHP_EOL;
		$content .= '<thead><tr><th>Pondělí</th><th>Úterý</th><th>Středa</th><th>Čtvrtek</th><th>Pátek</th><th>Sobota</th><th class="last-col">Neděle</th></tr></thead>' . PHP_EOL;
		$content .= '<tfoot><tr><th>Pondělí</th><th>Úterý</th><th>Středa</th><th>Čtvrtek</th><th>Pátek</th><th>Sobota</th><th class="last-col">Neděle</th></tr></tfoot>' . PHP_EOL;
		$content .= '<tbody>' . PHP_EOL;	
		
		if($firstdayIs > 1) {
			$content .= '<tr>';
			for($i=1; $i<$firstdayIs; $i++) {
				$content .= '<td>&nbsp;</td>';
			}
		}
    
		for($i=1; $i<$lastday+1; $i++) {
			$dayInWeek = intval(date('N', strtotime($year . '-' . $month . '-' . $this->_normalize_num($i))));
			
			if($dayInWeek == 1) {
				$content .= '<tr>' . PHP_EOL;
			}
			
      
			$dVal = $year . '-' . $this->_normalize_num($month) . '-' . $this->_normalize_num($i);
      
      $content .= '<td ' . (($dayInWeek == 7) ? ' class="last-col"' : '') . '>';
      
      $content .= (strtotime($dVal) < strtotime($_date)) 
          ? '<abbr title="' . __('Na uplynulé dny již nejde vytvářet rezervace.', self::TEXTDOMAIN) . '">'
          : '<a href="' . $url1 . '&amp;ds=' . $dVal . '">';
      
      $content .= '<strong' . (($_date == $dVal) ? ' style="color: #f30; font-size: 125%;"' : '') . '>' . $i . '</strong>';
      
      $content .= (strtotime($dVal) < strtotime($_date)) 
          ? '</abbr>' 
          : '</a>'; 
      
      // TODO Otestovat stav rezervaci na dany den!!!
      $status = ($this->_get_reservation_status_for_date($dVal) === true)
          ? '<span style="background-color: green; color: #fff;"> VOLNO </span>'
          : '<span style="background-color: #f30; color: #fff;"> OBSAZENO </span>';
      
      $content .= '<br/>Stav:<br/>' . $status . '</td>';
			
			if($dayInWeek == 7) {
				$content .= '</tr>' . PHP_EOL;
			}
		}
    
    if($dayInWeek < 7) {
      for($i=($dayInWeek+1); $i<=7; $i++) {
        $content .= '<td ' . (($i == 7) ? ' class="last-col"' : '') . '> </td>';
      }
    }
		
		$content .= '</tbody>' . PHP_EOL;
		$content .= '</table>' . PHP_EOL;
		
		$this->mRenderer->adminPage($title, $content, $icon);
	}
	
	/**
	 * Renders page with reservation select for the choosen date. 
	 * Called from `adminMain`.
	 * 
	 * @return void
	 */
	public function adminAddReservation()
	{
		$title = __('Rezervace - Výběr rezervace', self::TEXTDOMAIN);
		$url   = get_bloginfo('home') . '/wp-admin/admin.php?page=' . self::ID . '-reservation';
		$icon  = WP_PLUGIN_URL . '/' . self::ID . '/resources/icon32.png';
		$content = $content_inner = '';
    $options = $this->getOptions();
		$memberModel = new odReservationsWpPlugin_Models_Member();
		
    // Get default playground
    $playground = $this->_get_default_playground();
    if(is_null($playground)) {
      throw new Exception('Není nastaveno defaultní hřiště! Přejděte ' . 
                          'na stránku s nastavením pluginu a určete ' . 
                          'defaultní hřiště pro další pokračování.');
		}
    
    // Hodnoty se pokousi initializovat jak z GET parametru, tak i POST.
    // Az pote probehne test na to zda byl i ten formular odeslan ci zda 
    // nebylo stisknuto tlacitko `Predchozi`/`Nasledujici`
		
		// Vyber data (napr. '2010-04-08')
		$date = (array_key_exists('ds', $_GET)) 
				? date($_GET['ds']) 
				: ((array_key_exists('ds', $_POST)) ? $_POST['ds'] : null);
		
		// Vyber clena - pro administratory zobrazime vyber clenu klubu, 
    // pro cleny bude predvybrany on a bude si moci zvolit pouze pocet 
    // spoluhracu. Pokud neni ani administrator ani clen klubu ukoncime 
    // skript.
    $member_id = 0;
    $member = null;
    if($this->_is_logged_administrator() === true) {
      $member_id = (array_key_exists('us', $_GET))
          ? $_GET['us'] 
          : ((array_key_exists('us', $_POST)) ? $_POST['us'] : null);
      $member =  null;
      if(!is_null($member_id)) {
        $m = $memberModel->select('`t1`.`ID` = ' . intval($member_id));
        if(count($m) == 1) {
          $member = $m[0];
        } else {
          $content = '<p style="font-weigth: bold; color: #f30;"> '. sprintf(__('Uživatel s daným ID <code>%d</code> nebyl v databázi nalezen!', self::TEXTDOMAIN), $member_id) . '</p>';
          return $this->mRenderer->adminPage($title, $content, $icon);
        }
      }
    } else {
      $member = $this->_get_logged_member();
      
      if(!is_array($member)) {
        die(__('Nejste ani administrátoři ani členové klubu - nemáte ' . 
               'právo vytvářet objednávky.', self::TEXTDOMAIN));
      }
      
      $member_id = $member['ID'];
    }
    
    // Pocet spoluhracu
    $pc_max = (int) $playground['max_players'];
    $pc = (array_key_exists('pc', $_GET)) 
        ? (int) $_GET['pc'] 
        : ((array_key_exists('pc', $_POST)) ? $_POST['pc'] : 1);
    $pc = ($pc < 0) ? 0 : $pc;
    $pc = ($pc > $pc_max) ? $pc_max : $pc;
    
    // Vybrany cas
    $tm = (array_key_exists('tm', $_GET))
        ? (int) $_GET['tm']
        : ((array_key_exists('tm', $_POST)) ? $_POST['tm'] : null);
    
    // Nastavime spravnou stranku pruvodce - prvni urceni probehne na 
    // zaklade stavu jednotlivych promennych, ktere pruvodcem nastavujeme.
    $wizard_page = (array_key_exists('cwp', $_POST)) 
        ? (int) $_POST['cwp'] 
        : ((is_null($playground)) 
            ? 1 
            : ((is_null($date)) 
                ? 2 
                : ((is_null($member)) 
                    ? 3 
                    : 4)));
    
    $show_wizard = true;
    
    // Pote se resi stisknuti tlacitka `Predchozi`/`Nasledujici`
    if(array_key_exists('submit-prev', $_POST)) {
      $wizard_page = $wizard_page - 1;
    }
    elseif(array_key_exists('submit-next', $_POST)) {
      // Pokud je mensi nez 4 tak jen v klidu prochazime pruvodcem
      if($wizard_page < 4) {
        $wizard_page = $wizard_page + 1;
      } else { // v opacnem pripade se pokousime pruvodce uzavrit
        $reservationModel = new odReservationsWpPlugin_Models_Reservation();
        $res = $reservationModel->insert(array(
          'member_ID' => $member_id,
          'playground_ID' => $playground['ID'],
          'playmates' => $pc, 
          'start' => $date . ' ' . $this->_normalize_num($tm) . ':00:00'
        ));
        
        $content .= ($res === true)
            ? '<p><strong>' . __('Vaše rezervace byla úspěšně uložena!', self::TEXTDOMAIN) . '</strong></p>'
            : '<p style="color: #f30;"><strong>' . __('Litujeme, ale Vaše rezervace nebyla uložena! Opakujte rezervaci a v případě opakovaných potíží informujte administrátora stránek. Děkujeme.', self::TEXTDOMAIN) . '</strong></p>';
        $show_wizard = false;
        
        // TODO Pri dokonceni rezervace take hraci musime odecist body!!!
        
      }
    }
    
    // Zobrazime pruvodce
    if($show_wizard === true) {
      $matrix = $this->_get_reservations_matrix($playground, $date);
      if(!is_null($date) && !is_null($member)) {
        $content .= $this->_get_time_table_for_date($matrix, $playground, $date);
      }
      $content .= $this->_get_reservation_wizard($wizard_page, $playground, $date, $member, $pc, $tm, $matrix);
		}
    
		$this->mRenderer->adminPage($title, $content, $icon);
	}
	
  /**
   * Renders wizard for add reservation page.
   * 
   * @todo Create adaptation of `odWpPlugin_Form` => `odWpPlugin_Wizard` 
   *       with base functionality (mainly paging and required custom  
   *       form's elements).
   * 
   * @param integer $aPage Wizard's page.
   * @param array|null $aPlayground
   * @param string|null $aDate
   * @param array|null $aPlayer
   * @param integer $aPlaymatesCount Count of players.
   * @param string|null $aTime
   * @returns string
   */
	protected function _get_reservation_wizard($aPage = 1, 
                                             $aPlayground = null, 
                                             $aDate = null, 
                                             $aPlayer = null, 
                                             $aPlaymatesCount = 1, 
                                             $aTime = null, 
                                             $aMatrix = array())
	{
		if(!is_numeric($aPage)) $aPage = 1;
    if($aPage < 1 || $aPage > 4) $aPage = 1;
    
		$url = get_bloginfo('home') . '/wp-admin/admin.php?page=' . self::ID . '-reservation';
    $can_go_prev = true;
    $can_go_next = true;
    $content_inner = '';
    
		if($aPage == 1) {
      // {{{ Playground
			$img1 = 'icon-red-one.gif';
			$img2 = 'icon-gray-two.gif';
			$img3 = 'icon-gray-tree.gif';
			$img4 = 'icon-gray-four.gif';
			
			$content_inner .= '<strong>' . $aPlayground['title'] . '</strong>';
      $can_go_prev = false;
      // --- }}}
		} else if($aPage == 2) {
			// {{{ Date
      $img1 = 'icon-blue-one.gif';
			$img2 = 'icon-red-two.gif';
			$img3 = 'icon-gray-tree.gif';
			$img4 = 'icon-gray-four.gif';
      
      $content_inner .= '<input id="datepicker" name="ds" value="' . (is_null($aDate) ? date('Y-m-d') : $aDate) . '" type="text"/>';
      $content_inner .= '<script type="text/javascript">' . PHP_EOL . 
          'jQuery(document).ready(function() { ' . 
          '  jQuery("#datepicker").datepicker({ dateFormat: "yy-mm-dd"});' . 
          '});' . PHP_EOL . 
          '</script>';
      $content_inner .= '<br/>';
      // --- }}}
      $can_go_prev = false;
		} else if($aPage == 3) {
      // {{{ Hrac a pocet spoluhracu
			$img1 = 'icon-blue-one.gif';
			$img2 = 'icon-blue-two.gif';
			$img3 = 'icon-red-tree.gif';
			$img4 = 'icon-gray-four.gif';
      
      $current_member = $this->_get_logged_member();
      $memberModel = new odReservationsWpPlugin_Models_Member();
			$members = $memberModel->select('`t1`.`deleted` = 0');
      $no_members = true;
      $options = '';
      if($members !== false/* && $this->_is_logged_administrator() === true*/) {
        if(count($members) > 0) {
          $no_members = false;
          foreach($members as $member) {
            if(is_array($member)) {
              $selected = '';
              
              // TODO Tohle by jsme si mohli usetrit, kdyby jsme uz na zacatku 
              //      pouzili bud $aMember nebo $current_member v jine promenne.
              if(is_array($aPlayer)) {
                $selected = ($aPlayer['ID'] == $member['ID'])
                    ? ' selected="selected"'
                    : '';
              } elseif(is_array($current_member)) {
                $selected = ($current_member['ID'] == $member['ID'])
                    ? ' selected="selected"'
                    : '';
              }
              
              $options .= '<option value="' . $member['ID'] . '"' . $selected . '>' . $member['fullname'] . ' (' . $member['member_num'] . ')</option>';
            }
          }
        }
      }
      
      if($no_members === true) {
        $content_inner .= '<strong style="color:#f30;">' . __('Nejsou vytvořeni žádní uživatelé!', self::TEXTDOMAIN) . '</strong><br/>' . PHP_EOL;
        $can_go_next = false;
      } else {
        // TODO Select correct member!
        $content_inner .= '<label for="us">' . __('Vyberte uživatele:', self::TEXTDOMAIN) . '</label><br/>';
        if(!is_null($aPlayer) && $this->_is_logged_administrator() !== true) {
					$content_inner .= '<strong>' . $aPlayer['fullname'] . '</strong><br/>';
				} elseif(is_null($aPlayer)) {
          $content_inner .= '<select name="us" value="' . $aPlayer['ID'] . '" style="width: 180px;">' . $options . '</select><br/>';
        } elseif(is_array($current_member)) {
          $content_inner .= '<select name="us" value="' . $current_member['ID'] . '" style="width: 180px;">' . $options . '</select><br/>';
        } else {
          $content_inner .= '<select name="us" value="---" style="width: 180px;">' . $options . '</select><br/>';
        }
        
        $content_inner .= '<label for="pc">' . __('Vyberte počet spoluhráčů:', self::TEXTDOMAIN) . '</label>';
        if(!is_null($aPlaymatesCount)) {
          $content_inner .= '<select name="pc" value="' . $aPlaymatesCount . '" style="width: 180px;">';
        } else {
          $content_inner .= '<select name="pc" value="---" style="width: 180px;">';
        }
        
        for($i=0; $i<4; $i++) {
          $selected = (($i == $aPlaymatesCount) ? ' selected="selected"' : '');
          $content_inner .= '<option value="' . $i . '"' . $selected . '>' . $i . '</option>';
        }
        $content_inner .= '</select>';
      }
		} else if($aPage == 4) {
      // {{{ Cas zacatku rezervace
			$img1 = 'icon-blue-one.gif';
			$img2 = 'icon-blue-two.gif';
			$img3 = 'icon-blue-tree.gif';
			$img4 = 'icon-red-four.gif';
      
      
      // Na zaklade stavu rezervaci pro dany den a poctu hracu vybereme 
      // hodiny vhodne k zahajeni.
      $hours_per_game = (int) $aPlayground['hours_per_game'];
      $available_hours = $this->_get_available_hours($aMatrix, $aPlaymatesCount + 1, $hours_per_game);
      
      if(count($available_hours) > 0) {
        $content_inner .= '<label for="tm">' . __('Čas zahájení:', self::TEXTDOMAIN) . '</label><br/>' . PHP_EOL;
        $content_inner .= '<select name="tm">' . PHP_EOL;
        foreach($available_hours as $hour) {
          $content_inner .= '<option value="' . $hour .'">' . $hour . ':00</option>' . PHP_EOL;
        }
        $content_inner .= '</select>' . PHP_EOL;
      } else {
        $content_inner .= '<strong style="color: #f30;">' . __('Nelze vytvářet rezervace', self::TEXTDOMAIN) . '</strong>' . PHP_EOL;
        $can_go_next = false;
      }
      // --- }}}
		}
		
		$output = '';
    $output .= '<h3 style="margin-bottom:0px; padding-bottom: 0px;">Zadejte rezervaci</h3>' . PHP_EOL;
		$output .= '<form action="' . $url . '" method="POST" style="padding-left: 20px;">' . PHP_EOL;
    $output .= '<input name="cwp" type="hidden" value="' . $aPage . '"/>' . PHP_EOL;
		$output .= ((!is_null($aPlayground) && $aPage != 1) ? '<input name="pg" type="hidden" value="' . $aPlayground['ID'] .'"/>' . PHP_EOL : '');
		$output .= ((!is_null($aDate) && $aPage != 2) ? '<input name="ds" type="hidden" value="' . $aDate . '"/>' . PHP_EOL : '');
		$output .= (((!is_null($aPlayer) && $aPage != 3) || (!is_null($aPlayer) && $this->_is_logged_administrator() !== true)) ? '<input name="us" type="hidden" value="' . $aPlayer['ID'] . '"/>' . PHP_EOL : '');
		$output .= ((!is_null($aPlaymatesCount) && $aPage != 4) ? '<input name="pc" type="hidden" value="' . $aPlaymatesCount . '"/>' . PHP_EOL : '');
		$output .= ((!is_null($aTime)) ? '<input name="tm" type="hidden" value="' . $aTime . '"/>' . PHP_EOL : '');
		$output .= '<div style="padding-top: 40px; padding-bottom: 20px;">' . PHP_EOL;
		$output .= '<table id="wizard-table" cellspacing="0" cellpadding="1">' . PHP_EOL;
		$output .= '<tr>' . PHP_EOL;
		$output .= '<td class="style1" rowspan="2"><img src="' . $this->getResourceUrl('resources/img/' . $img1) . '"/></td>' . PHP_EOL;
		$output .= '<td class="style2">' . __('Hřiště', self::TEXTDOMAIN) . '</td>' . PHP_EOL;
		$output .= '<td class="style1" rowspan="2"><img src="' . $this->getResourceUrl('resources/img/' . $img2) . '"/></td>' . PHP_EOL;
		$output .= '<td class="style2">' . __('Datum', self::TEXTDOMAIN) . '</td>' . PHP_EOL;
		$output .= '<td class="style1" rowspan="2"><img src="' . $this->getResourceUrl('resources/img/' . $img3) . '"/></td>' . PHP_EOL;
		$output .= '<td class="style2">' . __('Hráči', self::TEXTDOMAIN) . '</td>' . PHP_EOL;
		$output .= '<td class="style1" rowspan="2"><img src="' . $this->getResourceUrl('resources/img/' . $img4) . '"/></td>' . PHP_EOL;
		$output .= '<td class="style2">' . __('Čas', self::TEXTDOMAIN) . '</td>' . PHP_EOL;
		$output .= '</tr>' . PHP_EOL;
		$output .= '<tr>' . PHP_EOL;
		$output .= '<td class="style3">' . (($aPage == 1) ? $content_inner : '<strong>' . $aPlayground['title'] . '</strong>') . '</td>' . PHP_EOL;
		$output .= '<td class="style3">' . (($aPage == 2) ? $content_inner : '<strong>' . $aDate . '</strong>') . '</td>' . PHP_EOL;
		$output .= '<td class="style3">' . (($aPage == 3) ? $content_inner : '<strong>' . $aPlayer['fullname'] . '</strong><br/>' . __('Počet spoluhráčů: ', self::TEXTDOMAIN) . $aPlaymatesCount) . '</td>' . PHP_EOL;
		$output .= '<td class="style3">' . (($aPage == 4) ? $content_inner : '<strong>' . $aTime . '</strong>') . '</td>' . PHP_EOL;
		$output .= '</tr>';
		$output .= '</table>';
		$output .= '</div>';
		$output .= '<p style="text-align: center;">';
    $output .= (($can_go_prev === true) 
        ? '<input type="submit" name="submit-prev" class="button-secondar action" value="' . __('Zpět', self::TEXTDOMAIN) . '"/>' 
        : '<input type="submit" name="submit-prev" class="button-secondar action" value="' . __('Zpět', self::TEXTDOMAIN) . '" style="cursor: default; opacity: 0.5; color: #ccc!important; border: 1px solid #06a!important;" disabled="disabled"/>') . '&nbsp;&nbsp;&nbsp;';
		$output .= (($can_go_next === true) 
        ? '<input type="submit" name="submit-next" class="button-primary action" value="' . __('Pokračovat', self::TEXTDOMAIN) . '"/>' 
        : '<input type="submit" name="submit-next" class="button-primary action" disabled="disabled" value="' . __('Pokračovat', self::TEXTDOMAIN) . '" style="cursor: default; opacity: 0.5; color: #ccc!important; border: 1px solid #06a!important;"/>');
		$output .= '</p>';
    $output .= '</form>';
		
		return $output;
	}
  
  /**
   * Render admin page with reservations of logged member's.
   * 
   * @return void
   */
  public function adminMyReservations()
  {
    $title = __('Rezervace - Moje rezervace', self::TEXTDOMAIN);
    $url   = get_bloginfo('home') . '/wp-admin/admin.php?page=' . self::ID . '-my_reservations';
    $icon  = WP_PLUGIN_URL . '/' . self::ID . '/resources/icon32.png';
    $reservationTable = new odReservationsWpPlugin_Tables_Reservation();
    $content = $reservationTable->render();
    
    $this->mRenderer->adminPage($title, $content, $icon);
  }
  
  /**
   * Render admin page with all reservations.
   * 
   * @return void
   */
  public function adminAllReservations()
  {
    $title = __('Rezervace - Přehled rezervací', self::TEXTDOMAIN);
    $url = get_bloginfo('home') . '/wp-admin/admin.php?page=' . self::ID . '-all_reservations';
    $icon = WP_PLUGIN_URL . '/' . self::ID . '/resources/icon32.png';
    $reservationTable = new odReservationsWpPlugin_Tables_Reservation();
    $reservationTable->showColumn('member_name');
    $content = $reservationTable->render();
    
    $this->mRenderer->adminPage($title, $content, $icon);
  }
    
	/**
	 * Render admin page for members.
	 *
	 * @return void
	 */
	public function adminMembers() 
	{
		$title = __('Rezervace - Uživatelé', self::TEXTDOMAIN);
		$url   = get_bloginfo('home') . '/wp-admin/admin.php?page=' . self::ID . '-members';
		$icon  = WP_PLUGIN_URL . '/' . self::ID . '/resources/icon32.png';
		$memberTable = new odReservationsWpPlugin_Tables_Member();
		$content = $memberTable->render();
		
		$this->mRenderer->adminPage($title, $content, $icon);
	}
  
	/**
	 * Renders add/edit member page.
	 *
	 * @return void
	 */
	public function adminAddMember()
	{
		$title = __('Rezervace - Přidej uživatele', self::TEXTDOMAIN);
		$icon  = WP_PLUGIN_URL . '/' . self::ID . '/resources/icon32.png';
		$formUrl = get_bloginfo('home') .'/wp-admin/admin.php?page=' . self::ID . '-add_member';
		$memberForm = new odReservationsWpPlugin_Forms_Member();
		$memberForm->setValue('op', 'add');
		
		if(isset($_GET['item_ID']) && !isset($_POST['op'])) {
      #{{{ User want to edit existing user ---
			$model = new odReservationsWpPlugin_Models_Member();
			$item_id = (int) $_GET['item_ID'];
			$title = __('Rezervace - Edituj uživatele #', self::TEXTDOMAIN) . $item_id;
			$item = $model->select('`t1`.ID = ' . $item_id);
			$item[0]['password'] = '';
			$item[0]['op'] = 'edit';
			$memberForm->setValues($item[0]);
      $memberForm->setElementProperty('login', 'disabled', true);
      //$memberForm->setElementProperty('password', 'disabled', true);
      //$memberForm->setElementProperty('password_repeat', 'disabled', true);
      #--- }}}
		}
		else if(isset($_POST['op'])) {
      //{{{ User submitted form ---
			$id = $_POST['ID'];
			$op = $_POST['op'];
			$memberModel = new odReservationsWpPlugin_Models_Member();
			$values = array(
				'login' => $_POST['login'],
				'pass1' => $_POST['password'],
				'pass2' => $_POST['password_repeat'],
				'surname' => $_POST['surname'],
				'firstname' => $_POST['firstname'],
				'street' => $_POST['street'],
				'town' => $_POST['town'],
				'zip' => $_POST['zip'],
				'email' => $_POST['email'],
				'phone' => $_POST['phone'], 
				'member_num' => $_POST['member_num'],
				'credits_ordered' => $_POST['credits_ordered'],
				'credits_left' => $_POST['credits_left'],
				'deleted' => false
			);
			
			if($op == 'add' && empty($id)) {
        #{{{ Add new item ---
				if($model->checkIfLoginExists($values['login'])) {
					$memberForm->setDescription('<p style="font-weight:bold;">' . __('Zadané přihlašovací jméno je již použito, prosíme, zvolte jiné.', self::TEXTDOMAIN) . '</p>');
          $memberForm->setValue('op', 'add');
					$memberForm->setValues($values);
				}
				else if(empty($values['login'])) {
					$memberForm->setDescription('<p style="font-weight:bold;">' . __('Nevyplnili jste správně všechny vyžadované hodnoty!', self::TEXTDOMAIN) . '</p>');
					$memberForm->setValue('op', 'add');
					$memberForm->setValues($values);
				}
				else if(empty($values['pass1']) || $values['pass1'] != $values['pass2']) {
					$memberForm->setDescription('<p style="font-weight:bold;">' . __('Nezadali jste heslo pro uživatele nebo si zadaná hesla neodpovídají!', self::TEXTDOMAIN) . '</p>');
					$memberForm->setValue('op', 'add');
					$memberForm->setValues($values);
				}
				else {
					$values['credits_left'] = $values['credits_ordered'];
					$userdata = array(
						'ID'         => '',
						'user_login' => $values['login'],
						'user_pass'  => $values['pass1'],
						'user_nicename' => '',
						'user_url' => '',
						'user_email' => $values['email'],
						'display_name' => '',
						'nickname' => '',
						'first_name' => $values['firstname'],
						'last_name' => $values['surname'],
						'description' => '',
						'rich_editing' => 'false',
						'comments_shortcuts' => 'true',
						'admin_color' => 'fresh',
						'use_ssl' => 0,
						'jabber' => '',
						'aim' => '',
						'yim' => '',
						'user_registered' => '',
						'role' => 'golfmember'
					);
					$wp_user_id = wp_insert_user($userdata);
					
					$values['wp_user_ID'] = $wp_user_id;
					unset($values['login']);
					unset($values['pass1']);
					unset($values['pass2']);
					unset($values['firstname']);
					unset($values['surname']);
					unset($values['email']);
					
					$res = $memberModel->insert($values);
					if($res) {
						$memberForm->setDescription('<p style="font-weight:bold;">' . __('Nový uživatel byl úspěšně vytvořen.', self::TEXTDOMAIN) . '</p>');
					} else {
						$memberForm->setDescription('<p style="font-weight:bold;">' . __('Při ukládání nového uživatele do databáze se vyskytla neznámá chyba!', self::TEXTDOMAIN) . '</p>');
					}
				}
        #--- }}}
			} 
			else {
				#{{{ Save edited item ---
        if((!empty($values['pass1']) && !empty($values['pass2'])) && 
           ($values['pass1'] != $values['pass2'])) {
					$memberForm->setDescription('<p style="font-weight:bold;">' . __('Zadaná hesla neodpovídají!', self::TEXTDOMAIN) . '</p>');
					$memberForm->setValues($values);
				}
				else {
					$userdata = array(
						//'user_login' => $values['login'],
						//'user_pass'  => $values['pass1'],
						'user_email' => $values['email'],
						'first_name' => $values['firstname'],
						'last_name' => $values['surname']
					);
          if(!empty($values['pass1']) && !empty($values['pass2'])) {
            $userdata['user_pass'] = $values['pass1'];
          }
					// $wp_user_id = wp_insert_user($userdata);
          // TODO Update WordPress user!!!
					
					$values['wp_user_ID'] = $wp_user_id;
					unset($values['login']);
					unset($values['pass1']);
					unset($values['pass2']);
					unset($values['firstname']);
					unset($values['surname']);
					unset($values['email']);
					
					//$res = $memberModel->insert($values);
          // TODO Update user data!!!
					if($res) {
						$memberForm->setDescription('<p style="font-weight:bold;">' . __('Nový uživatel byl úspěšně vytvořen.', self::TEXTDOMAIN) . '</p>');
					} else {
						$memberForm->setDescription('<p style="font-weight:bold;">' . __('Při ukládání nového uživatele do databáze se vyskytla neznámá chyba!', self::TEXTDOMAIN) . '</p>');
					}
				}
        #--- }}}
      }
      #--- }}}
		}
    
		$memberForm->setElementProperty(
			'password_repeat', 
			'description', 
			__('Hesla vložte pouze v případě, že je chcete změnit!', self::TEXTDOMAIN)
		);
		
		$this->mRenderer->adminPage($title, $memberForm->render(), $icon);
	}
	
	/**
	 * Render admin page for playgrounds.
	 *
	 * @return void
	 */
	public function adminPlaygrounds() 
	{
		$title = __('Rezervace - Hřiště', self::TEXTDOMAIN);
		$url   = get_bloginfo('home') .'/wp-admin/admin.php?page=' . self::ID . '-playgrounds';
		$icon  = WP_PLUGIN_URL . '/' . self::ID . '/resources/icon32.png';
		$playgroundTable = new odReservationsWpPlugin_Tables_Playground();
		$content = $playgroundTable->render();
		
		$this->mRenderer->adminPage($title, $content, $icon);
	}
  
	/**
	 * Renders add/edit playground page.
	 *
	 * @return void
	 */
	public function adminAddPlayground()
	{
		$title = __('Rezervace - Přidej hřiště', self::TEXTDOMAIN);
		$icon  = WP_PLUGIN_URL . '/' . self::ID . '/resources/icon32.png';
		$formUrl = get_bloginfo('home') .'/wp-admin/admin.php?page=' . self::ID . '-add_playground';
		$playgroundForm = new odReservationsWpPlugin_Forms_Playground();
		$playgroundForm->setValues(array('op' => 'add'));
    
		if(isset($_GET['item_ID'])) {
			$playgroundModel = new odReservationsWpPlugin_Models_Playground();
			$item_id = (int) $_GET['item_ID'];
			$title = __('Rezervace - Edituj hřiště #', self::TEXTDOMAIN) . $item_id;
			$item = $playgroundModel->select('`t1`.ID = ' . $item_id);
			$playgroundForm->setValues($item[0]);
		}
		else if(isset($_POST['op'])) {
			$id = $_POST['ID'];
			$op = $_POST['op'];
			$playgroundModel = new odReservationsWpPlugin_Models_Playground();
			$values = array(
				'title' => $_POST['title'],
				'deleted' => 0
			);
			
			if($op == 'add' && empty($ID)) {
				// Pridej nove hriste
        if(empty($values['title'])) {
					$playgroundForm->setDescription('<p style="font-weight:bold;">' . __('Nevyplnili jste název nového hřiště!', self::TEXTDOMAIN) . '</p>');
					$playgroundForm->setValues($values);
				}
				else {
					$res = $playgroundModel->insert($values);
					if($res) {
						$playgroundForm->setDescription('<p style="font-weight:bold;">' . __('Nové hřiště bylo úspěšně vytvořeno.', self::TEXTDOMAIN) . '</p>');
					} else {
						$playgroundForm->setDescription('<p style="font-weight:bold;">' . __('Při ukládání nového hřiště do databáze se vyskytla neznámá chyba!', self::TEXTDOMAIN) . '</p>');
					}
				}
			}
			else {
        // Aktualizuj stavajici hriste
        $item_id = (int) $_POST['ID'];
        $playgroundModel->update($values, '`ID` = ' . $item_ID);
        $playgroundForm->setDescription('<p style="font-weight:bold;">' . __('Položka byla úspěšně aktualizována.', self::TEXTDOMAIN) . '</p>');
			}
		}
		
    $content = $playgroundForm->render();
    
		$this->mRenderer->adminPage($title, $content, $icon);
	}
  
	/** 
	 * Renders settings page for the plugin
	 * 
	 * @return void
	 */
	public function adminSettings()
	{
		$title = __('Rezervace - Nastavení', self::TEXTDOMAIN);
		$icon  = WP_PLUGIN_URL . '/' . self::ID . '/resources/icon32.png';
		$formUrl = get_bloginfo('home') .'/wp-admin/admin.php?page=' . self::ID . '-settings';
		$options = $this->getOptions();
		
		if(isset($_POST['settings_save'])){
			$options['default_playground_id'] = (int) $_POST['option-default_playground_id'];
			update_option(self::ID . '-options', $options);
			
			$this->mRenderer->adminMsg(__('Nastavení pluginu bylo aktualizováno.', self::TEXTDOMAIN));
		}
		
		$content  = '<form action="' . $formUrl . '" method="post" enctype="multipart/form-data">' . PHP_EOL;
		$content .= '	<div>' . PHP_EOL;
		$content .= '		<table class="widefat post fixed" cellpadding="1" cellspacing="1" style="100%;">' . PHP_EOL;
		$content .= '			<tr>' . PHP_EOL;
		$content .= '				<th scope="row"><label for="option-default_playground_id">' . __('ID defaultního hřiště:', self::TEXTDOMAIN) . '</label></th>' . PHP_EOL;
		$content .= '				<td><input type="text" name="option-default_playground_id" value="' . $options['default_playground_id'] . '" style="width: 50px;"/></td>' . PHP_EOL;
		$content .= '			</tr>' . PHP_EOL;
		$content .= '		</table>' . PHP_EOL;
		$content .= '		<input type="submit" value=" ' . __('Save', self::TEXTDOMAIN) . ' " name="settings_save" class="button-primary action" />' . PHP_EOL;
		$content .= '	</div>' . PHP_EOL;
		$content .= '</form>' . PHP_EOL;
		
		$this->mRenderer->adminPage($title, $content, $icon);
	}
  
  /** 
   * Returns URL to the plugin's directory with ending '/'. 
   * E.g.: http://www.ondrejd.com/wp-content/plugins/od-reservations-plugin/
   * 
   * @todo This should be located in `odWpPlugin`!
   * 
   * @return string
   */
  public function getUrl()
  {
    return WP_PLUGIN_URL . '/' . self::ID . '/';
  }
  
  /**
   * Returns URL to the given plugin's resource.
   * 
   * @param string $aResourcePath
   * @return string
   */
  public function getResourceUrl($aResourcePath) 
  {
    return $this->getUrl() . ((is_string($aResourcePath)) ? $aResourcePath : '');
  }
	
	/**
   * Normalize integer number (if are lesser than 10 add leading zero).
   * 
   * @param string|integer $aNum
   * @return string
   */
	protected function _normalize_num($aNum) 
  { 
		$n = intval($aNum); 
    
		return ($n < 10) ? "0{$n}" : "{$n}"; 
	}
  
  /**
   * Returns currently logged member. If currently logged user is not 
   * a member returns NULL.
   * 
   * @return array|null
   */
  protected function _get_logged_member()
  {
		global $current_user;
    
    $memberModel = new odReservationsWpPlugin_Models_Member();
    $member = $memberModel->select('`t1`.`wp_user_ID` = ' . $current_user->ID . ' ');
    
    return (count($member) == 1) ? $member[0] : null;
  }
  
  /**
   * Returns TRUE if logged user is an admin - used for recognization 
   * of those administrations who are also members.
   * 
   * @return boolean
   */
  protected function _is_logged_administrator()
  {
    global $current_user;
    
    return in_array('administrator', $current_user->roles);
  }
	
  /** 
   * Returns default playground.
   * 
   * @return array|NULL
   */
  protected function _get_default_playground()
  {
		$options = $this->getOptions();
		$playground_id = (int) $options['default_playground_id'];
		$playgroundModel = new odReservationsWpPlugin_Models_Playground();
		$playground = $playgroundModel->select('`t1`.`ID` = ' . $playground_id);
    
    return (count($playground) == 1) ? $playground[0] : null;
  }
  
  /**
   * Check if are given hours free for a new game.
   * 
   * @param array $aHours
   * @param integer $aStartHour
   * @param integer $aEndHour
   * @return boolean
   */
  protected function _are_hours_free($aHours, $aStartHour, $aEndHour) 
  {
    $res = true;
    for($i=$aStartHour; $i<$aEndHour; $i++) {
      $res &= (is_null($aHours[$i])) ? true : $aHours[$i];
    }
    return $res;
  }
  
  /**
   * Returns array with reservation matrix on the given date and specified 
   * playground.
   * 
   * @param array $aPlayground
   * @param string|NULL $aDate If NULL the current date is used.
   * @return boolean
   */
  protected function _get_reservations_matrix($aPlayground, $aDate = null)
  {
    if(!is_array($aPlayground)) {
      throw new Exception('Playground should be specified!');
    }
    
    $date = (is_null($aDate)) ? date('Y-m-d') : $aDate;
    $reservationModel = new odReservationsWpPlugin_Models_Reservation();
    
    $reservations = $reservationModel->select(
      '( `t1`.`start` > \'' . $date . ' 00:00:00\' AND' . 
      '  `t1`.`start` < \'' . $date . ' 24:00:00\') AND' . 
      '  `t1`.`playground_ID` = ' . $aPlayground['ID'] . ' AND' . 
      '  `t1`.`cancelled` = 0 ', 
      0, 
      0, 
      '`t1`.`start` ASC '
    );
    
    // Maximalni pocet hracu naraz
    $max_players_at_once = (int) $aPlayground['max_players'];
    // Cas po ktery muze trvat jedna hra
    $hours_per_game = (int) $aPlayground['hours_per_game'];
		// Casy od kterych lze zapocit rezervaci
		$start_times = unserialize($aPlayground['start_times']);
    // Casy si musime normalizovat (ty hodiny, v ktere nelze zapocit 
    // nova rezervace, nastavime jako NULL)
    foreach($start_times as $starttime_key => $starttime)
      $start_times[$starttime_key] = ($starttime === false) ? null : true;
    
    // Pomocna promenna - celkovy pocet startovacich casu
    $slots_count = count($start_times);
    // Pomocne promenna - pole casu pro hrace (TRUE=volno, FALSE=obsazeno)
    $slots = array();
    for($i=0; $i<$max_players_at_once; $slots[$i++] = $start_times);
    
    // {{{ Sestavime matrici vsech hodin a jejich aktualniho stavu
    if(count($reservations) > 0) {
      foreach($reservations as $reservation) {
        $starttime = (int) str_replace(':00:00', '', 
            str_replace($date . ' ', '', $reservation['start']));
        $endtime = $starttime + $hours_per_game;
        // TODO Tady nema byt posledni hodina zadana primo!!!
        $endtime = ($endtime > 21) ? 21 : $endtime;
        $players = 1 + (int) $reservation['playmates'];
        
        for($i=0; $i<$players; $i++) {
          for($ii=0; $ii<$max_players_at_once; $ii++) {
            if($this->_are_hours_free($slots[$ii], $starttime, $endtime) && $players > 0) {
              $players = $players - 1;
              for($iii=$starttime;  $iii < $endtime; $slots[$ii][$iii++] = false);
            }
          }
        }
      }
    }
    // --- }}}
    
    // {{{ debug vypis 
    /*
    echo '<strong>Den:</strong> ' . $date . ',&nbsp;' . 
         '<strong>Hriste:</strong> ' . $aPlayground['title'] . '&nbsp' . 
         '(<abbr title="Max. pocet hracu najednou.">' . $max_players_at_once . '</abbr> x ' . 
         '<abbr title="Hodin na hru.">' . $hours_per_game . '</abbr>)<br/>';
    //echo '<strong>Rezervace:</strong><br/><code>' . serialize($reservations) . '</code><br/>';
    echo '<pre>';
    for($i=0; $i<$max_players_at_once; $i++) {
      echo '<strong>#' . ($i+1) . '</strong>&nbsp;<code>' . 
          str_replace(';N', '=<strong>-</strong>', str_replace('=0', '=<strong style="color:#f30;">0</strong>', str_replace('=1', '=<strong style="color:green;">1</strong>', str_replace(';}', '', str_replace('{i:', '', str_replace('a:14:', '', str_replace(';b:', '=', str_replace(';i:', '|', serialize($slots[$i]))))))))) . 
          '</code><br/>';
    }
    echo '</pre>';
    //echo '<strong>JE HRISTE JESTE VOLNE:</strong> ' . (($is_free===true) ? '<strong style="color: green;">ANO</strong>' : '<strong style="color: #f30;">NE</strong>') . '<hr/>';
    */
    // --- }}}
    
    return $slots;
  }
  
  /**
   * Returns TRUE if given date is not full and allow more reservations 
   * or FALSE if not.
   * 
   * @param string|NULL $aDate If NULL the current date is used.
   * @return boolean
   */
  protected function _get_reservation_status_for_date($aDate = null)
  {
    // Use current date or given
    $date = (is_null($aDate)) ? date('Y-m-d') : $aDate;
    
    // Get default playground
    $playground = $this->_get_default_playground();
    if(is_null($playground)) {
      throw new Exception('Není nastaveno defaultní hřiště! Přejděte ' . 
                          'na stránku s nastavením pluginu a určete ' . 
                          'defaultní hřiště pro další pokračování.');
		}
    
    // Matrix contains array with available places and hours. If field 
    // is NULL cann't be used for reservation, if TRUE can be reserved, 
    // FALSE means that is already reserved.
    $matrix = $this->_get_reservations_matrix($playground, $date);
    
    // {{{ Otestujeme zda je jeste nekde volno, po prvnim nalezu koncime
    $is_free = false;
    for($i=0; $i<(int) $playground['max_players']; $i++) {
      for($ii=9; $ii<18; $ii++) {
        if($matrix[$i][$ii] === true && 
           $this->_are_hours_free($matrix[$i], $ii, $ii+5)) {
          $is_free = true;
          break;
        }
      }
    }
    // --- }}}
    
    return $is_free;
  }
  
  /**
   * Returns array with hours from which can reservation be started 
   * (according to given reservation matrix, number of players and 
   * game length in hours).
   * 
   * @param array $aMatrix Matrix of hours and slots. Can be obtained 
   *                       from odReservationsWpPlugin::_get_reservations_matrix().
   * @param integer $aPlayers Number of players
   * @param integer $aHoursPerGame Hours for single play.
   * @return array
   */
  protected function _get_available_hours($aMatrix, $aPlayers, $aHoursPerGame)
  {
    $available_hours = array();
    
    foreach($aMatrix as $slot => $slot_data) {
      foreach($slot_data as $hour => $hour_status) {
        if($hour_status !== true) continue;
        if(count($aMatrix) < ($slot + $aPlayers)) continue;
        if(!$this->_are_hours_free($slot_data, $hour, $hour + 5)) continue;
        if(in_array($hour, $available_hours)) continue;
        
        $res = true;
        for($i=1; 
            $i<$aPlayers; 
            $res = $res && ($this->_are_hours_free($aMatrix[$i++ + $slot], $hour, $hour + 5)));
        
        !$res || array_push($available_hours, $hour);
      }
    }
    
    return $available_hours;
  }
  
  /**
   * Renders calendar with highlighted reservations for selected date.
   * 
   * @param array $aMatrix Matrix of hours and slots. Can be obtained 
   *                       from odReservationsWpPlugin::_get_reservations_matrix().
   * @param array $aPlayground 
   * @param string|NULL $aDate If NULL the current date is used.
   * @return string
   */
  protected function _get_time_table_for_date($aMatrix, $aPlayground, $aDate = null)
  {
    if(!is_array($aPlayground)) {
      throw new Exception('Playground should be specified!');
    }
    
    // Use current date or given
    $date = (is_null($aDate)) ? date('Y-m-d') : $aDate;
    // Cas po ktery muze trvat jedna hra
    $hours_per_game = (int) $aPlayground['hours_per_game'];
    
    $content = '';
		$content .= '<h3>' . __('Stav rezervací pro vybraný den:' , self::TEXTDOMAIN) . '</h3>' . PHP_EOL;
		/*
    $content .= '<script type="text/javascript">' . PHP_EOL . 
		'var hoverRunning = false;' . PHP_EOL . 
		'var outRunning = false;' . PHP_EOL . 
		'function onReservationTableHover(aRow, aIndex) {' . PHP_EOL . 
		'  if(hoverRunning == true) return;' . PHP_EOL . 
		'  hoverRunning = true;' . PHP_EOL . 
		'  for(var i=aIndex; i<(aIndex + ' . $hours_per_game . '); i++) {' . PHP_EOL . 
		'    document.getElementById("resCol" + i + "_" + aRow).style.backgroundColor="#555";' . PHP_EOL . 
		'  }' . PHP_EOL . 
		'  hoverRunning = false;' . PHP_EOL . 
		'} ' . PHP_EOL . 
		'function onReservationTableOut(aRow, aIndex, aColor) {' . PHP_EOL . 
		'  if(outRunning == true) return;' . PHP_EOL . 
		'  outRunning = true;' . PHP_EOL . 
		'  for(var i=aIndex; i<(aIndex + ' . $hours_per_game . '); i++) {' . PHP_EOL . 
		'    document.getElementById("resCol" + i + "_" + aRow).style.backgroundColor="#fff";' . PHP_EOL . 
		'  }' . PHP_EOL . 
		'  outRunning = false;' . PHP_EOL . 
		'}' . PHP_EOL .  
		'</script>' . PHP_EOL;
    */
		$content .= '<table id="add_reservation_overview_table" class="widefat post fixed" cellspacing="0">' . PHP_EOL;
		$content .= '<thead><tr><th>Hod.</th>';
		foreach($aMatrix[0] as $time => $can_start) {
			$content .= '<th>' . $time . '</th>';
		}
		$content .= '</tr></thead>' . PHP_EOL;
		$content .= '<tbody>' . PHP_EOL;
		for($i=0; $i<count($aMatrix); $i++) {
			$content .= '<tr><th class="slot_col">Pozice #' . ($i + 1) . ':</th>';
			$ii = 0;
			foreach($aMatrix[$i] as $time => $can_start) {
        if(is_null($can_start)) {
          $content .= 
              '<td class="na" id="resCol' . $ii . '_' . $i . '">-</td>' . PHP_EOL;
        } elseif($can_start === true) {
          $content .= 
              '<td class="free" id="resCol' . $ii . '_' . $i . '">' . 
              __('+', self::TEXTDOMAIN) . '</td>' . PHP_EOL; 
          /* $content .= 
              '<td class="free" id="resCol' . $ii . '_' . $i . '">' . 
              '<a href="#" onmouseover="onReservationTableHover(' . $i . ', ' . $ii . ');"' . 
						  ' onmouseout="onReservationTableOut(' . $i . ', ' . $ii . ', \'green\');"' . 
						  ' title="' . __('Objednat rezervaci vybraného času', self::TEXTDOMAIN) . '">' . 
              __('+', self::TEXTDOMAIN) . '</a></td>' . PHP_EOL; */
        } else {
          $content .= 
              '<td class="reserved" id="resCol' . $ii . '_' . $i . '" title="' . __('Rezervováno.', self::TEXTDOMAIN) . '">' . 
              __('0', self::TEXTDOMAIN) . '</td>' . PHP_EOL; 
        }
				$ii++;
			}
			$content .= '</tr>';
		}
		
		$content .= '</tbody>' . PHP_EOL;
		$content .= '</table>' . PHP_EOL;
    
    return $content;
  }
	
} // End of odReservationsWpPlugin

endif;
#}}} --- odReservationsWpPlugin


if(class_exists('odReservationsWpPlugin')):
// Initialize plugin
$od_catalog_wpplugin = odReservationsWpPlugin::getInstance();
endif;
